package com.fjec.common.redis;

import com.fjec.common.Const;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.redis.util.RedisLockRegistry;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

@Slf4j
public class RedisGenIdHelper {

    private static volatile int dataCenterId;

    private static volatile int workerId;

    private static volatile int seed;

    public static int getDataCenterId() {
        return dataCenterId;
    }

    public static int getWorkerId() {
        return workerId;
    }

    public static int getSeed() {
        return seed;
    }

    private RedisTemplate redisTemplate;

    private RedisLockRegistry redisLockRegistry;

    public RedisGenIdHelper(RedisTemplate redisTemplate,
                            RedisLockRegistry redisLockRegistry) {
        this.redisTemplate = redisTemplate;
        this.redisLockRegistry = redisLockRegistry;
    }

    /**
     * 生成Id配置
     *
     * @return
     * @throws Exception
     */
    @PostConstruct
    public void init() {
        Lock lock = redisLockRegistry.obtain(Const.GEN_ID_LOCK_KEY);
        try {
            boolean ret = lock.tryLock(10, TimeUnit.SECONDS);
            if (ret) {
                do {
                    seed = generateSeed();
                } while (this.seed == -1);
                dataCenterId = seed >> 5;
                workerId = seed & 0x1f;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private int generateSeed() {
        int i = 0;
        while (true) {
            String key = Const.DATACENTER_WORKER_KEY + ":" + i;
            Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, i);
            redisTemplate.expire(key, Const.DATACENTER_WORKER_TIMEOUT, TimeUnit.SECONDS);
            if (ret) {
                log.info("GenId get success!: {}", i);
                return i;
            }
            i++;
            if (i > 1024) {
                log.error("GenId error: seed > 1024");
                System.exit(500);
            }
        }
//        for (int i = 0; i < 1024; i++) {
//            String key = Const.DATACENTER_WORKER_KEY + ":" + i;
//            Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, i);
//            redisTemplate.expire(key, Const.DATACENTER_WORKER_TIMEOUT, TimeUnit.SECONDS);
//            if (ret) {
//                return i;
//            }
//        }
//        return -1;
    }

    public void loopCheck() {
        String key = Const.DATACENTER_WORKER_KEY + ":" + this.seed;
        if (redisTemplate.hasKey(key)) {
            redisTemplate.expire(key, Const.DATACENTER_WORKER_TIMEOUT, TimeUnit.SECONDS);
        } else {
            init();
        }
    }
}
